package pile.pay.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.apache.shardingsphere.api.hint.HintManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pile.pay.config.huifuPayConfig.*;
import pile.pay.entity.*;
import pile.pay.service.*;
import pile.pay.utils.EmailUtil;
import pile.pay.utils.HttpClientUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Log4j2
public class HuiFuPayServiceImpl implements IHuiFuPayService {

    @Autowired
    private IMemberSubsidiaryService memberSubsidiaryService;

    @Autowired
    private IRechargeService rechargeService;

    @Autowired
    private IRefundOrderService refundOrderService;

    @Autowired
    private IBalanceChangeService balanceChangeService;


    @Value("${huifupay.payNotify}")
    private String payNotify;

    @Value("${huifupay.refundsNotify}")
    private String refundsNotify;

    @Autowired
    private EmailUtil emailUtil;


    /**
     * 统一下单-统一接口
     *
     * @param tradePayment
     * @return
     */
    @Override
    @Transactional
    public ResponseResult transactions(TradePayment tradePayment) {


        String openid = tradePayment.getOpenid();

        //支付回调路径
        tradePayment.setNotify_url(payNotify);
        //如果前段不传openid 用数据库存的  以往万一
        if (StringUtils.isEmpty(openid)) {
            //根据类型和用户ID 查询openid
            MemberSubsidiary memberSubsidiary = memberSubsidiaryService.selectOpenidByType(tradePayment.getChannel(), tradePayment.getMemberId());
            openid = memberSubsidiary.getOpenid();
        }
        //根据用户ID查询openid
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        //时间
        tradePayment.setReq_date(sdf.format(new Date()));
        //商户号
        Recharge recharge = rechargeService.selectByRechargeOrderNoLock(tradePayment.getReq_seq_id());
        tradePayment.setHuifu_id(recharge.getMchId());
        //这里还需要写 ==4  支付宝的  支付宝类型不一样
        if (tradePayment.getChannel() == 3 || tradePayment.getChannel() == 1) {
            //汇付微信支付
            WeChatExtensionParameters weChatExtensionParameters = new WeChatExtensionParameters();
            //openid
            weChatExtensionParameters.setSub_openid(openid);
            //因为卫莱电切换主题 appid之前是写死的 是阿凡电的  现在卫莱电也需要用汇付

            if (tradePayment.getChannel() == 1) {
                weChatExtensionParameters.setSub_appid("wxb7e0dc50ce96fc39");
            }
            tradePayment.setWx_data(JSONUtil.toJsonStr(weChatExtensionParameters));
        }
        if (tradePayment.getChannel() == 4 || tradePayment.getChannel() == 2) {
            Map alipay_data = new HashMap();
            alipay_data.put("buyer_id", openid);
            tradePayment.setAlipay_data(JSONUtil.toJsonStr(alipay_data));

            tradePayment.setTrade_type("A_JSAPI");
        }
        tradePayment.setDelay_acct_flag("Y");
        String jsonString = JSON.toJSONString(JSONObject.parseObject(JSONUtil.toJsonStr(tradePayment), TreeMap.class));
        //获取sign
        String sign = HuiFuVerificationSignatures.sign(jsonString, HuiFuConstants.RSA_PRIVATE_KEY);

        CommonParameters<TradePayment> commonParameters = new CommonParameters<>();
        commonParameters.setSign(sign);
        commonParameters.setData(tradePayment);
        commonParameters.setSys_id(HuiFuConstants.SYS_ID);
        commonParameters.setProduct_id(HuiFuConstants.PRODUCT_ID);

        String returnResultsString = HttpClientUtil.doPostJson("https://api.huifu.com/v2/trade/payment/jspay", JSONUtil.toJsonStr(commonParameters));

        JSONObject jsonObject = JSON.parseObject(returnResultsString);

        //验签
        String data = jsonObject.get("data").toString();

        JSONObject dataObj = JSON.parseObject(data);
        if (!dataObj.get("resp_code").toString().equals("00000100")) {
            return new ResponseResult(203, jsonObject);
        }

        //log.info("宝付支付返回结果:"+returnResultsString);
        return new ResponseResult(200, dataObj);
    }

    @Override
    @Transactional
    public String payNotify(HttpServletRequest request, HttpServletResponse response) {

        String data = request.getParameter("resp_data");
        String reqSeqId = null;
        try {
            // 验签请参sign
            String sign = request.getParameter("sign");
            // 使用汇付公钥验签
            if (!HuiFuVerificationSignatures.verify(data, HuiFuConstants.RSA_PUBLIC_KEY, sign)) {
                // 验签失败处理
                log.error("汇付支付，支付回调验签失败");
                return "";
            }
            JSONObject dataObj = JSON.parseObject(data);
            String subRespCode = dataObj.getString("sub_resp_code");
            reqSeqId = dataObj.getString("req_seq_id");
            if (!"00000000".equals(subRespCode)) {
                log.error("汇付支付，回调支付状态不是交易中:" + data);
                return "RECV_ORD_ID_" + reqSeqId;
            }

            //强制读主库
            HintManager.getInstance().setMasterRouteOnly();


            //状态正确 进行逻辑处理
            // 结果正确  我们自己生成的订单号
            String orderId = dataObj.get("req_seq_id").toString();
            //微信支付单号
            String tradeNo = dataObj.get("bank_order_no").toString();
            //获取到支付的商户号 退款需要用到
            String partyOrderId = dataObj.get("party_order_id").toString();

            //实际支付金额 单位元
            String totalFee = dataObj.get("trans_amt").toString();
            //备注
            String remark = dataObj.get("remark").toString();
            BigDecimal totalAmount = new BigDecimal(totalFee);

            //根据订单号查询充值表信息
            Recharge recharge = rechargeService.selectByRechargeOrderNoLock(orderId);
            if (recharge == null) {
                log.error("汇付支付回调，充值订单不存在，回调参数:" + dataObj);
                return "RECV_ORD_ID_" + reqSeqId;
            }

            if (!(totalAmount.compareTo(recharge.getRechargeAmount()) == 0)) {
                //金额不一致 不管
                log.error("汇付支付回调，充值表金额与支付回调金额不一致，回调参数:" + dataObj);
                return "RECV_ORD_ID_" + reqSeqId;
            }
            if (recharge.getPaymentStatus() != 0) {
                //状态不是未支付
                log.error("汇付支付回调,充值表金额状态不是未支付:" + "微信支付单号:" + tradeNo);
                return "RECV_ORD_ID_" + reqSeqId;
            }
            //根据充电渠道判断是微信还是支付宝  给充值订单赋值支付渠道
            if (recharge.getChannel() == 1 || recharge.getChannel() == 3) {
                recharge.setPaymentChannel(3);
            } else if (recharge.getChannel() == 2 || recharge.getChannel() == 4) {
                recharge.setPaymentChannel(4);
            } else {
                log.error("汇付支付渠道错误" + recharge.getRechargeOrderNo());
            }
            ///获取到支付的商户号 退款需要用到
            recharge.setPartyOrderId(partyOrderId);
            //第三方订单号
            recharge.setThirdOrderNumber(tradeNo);


            //充值回调的逻辑 有三个支付 写一个公共的方法
            rechargeService.rechargeCallbackProcessLogic(recharge);

        } catch (Exception e) {
            log.error("异步回调开始报错，参数，request={}:" + data);
            log.error("异步回调开始报错，内容:" + e);
        } finally {
            //释放设置
            HintManager.clear();
        }
        return "RECV_ORD_ID_" + reqSeqId;
    }

    /**
     * 汇付退款回调
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {
        String data = request.getParameter("resp_data");

        String reqSeqId = null;
        try {
            // 验签请参sign
            String sign = request.getParameter("sign");
            // 使用汇付公钥验签
            if (!HuiFuVerificationSignatures.verify(data, HuiFuConstants.RSA_PUBLIC_KEY, sign)) {
                // 验签失败处理
                log.error("汇付退款回调验签失败:" + data);
                return "验签失败";
            }
            JSONObject dataObj = JSON.parseObject(data);
            String subRespCode = dataObj.getString("sub_resp_code");
            reqSeqId = dataObj.getString("req_seq_id");
            if (!"00000000".equals(subRespCode)) {
                // 业务处理失败
                log.error("汇付退款失败，状态码不是退款成功:" + data);
                return "RECV_ORD_ID_" + reqSeqId;
            }
            String transRefundInfoStr = dataObj.getString("trans_refund_info");

            JSONObject transRefundInfo = JSON.parseObject(transRefundInfoStr);

            String transactionId = transRefundInfo.getString("org_out_trans_id");

            //退款金额
            String refundAmount = dataObj.getString("ord_amt");

            //根据第三方支付单号查询 充值表数据
            Recharge recharge = rechargeService.selectByTransactionIdLock(transactionId);


            RefundOrder refundOrder = refundOrderService.selectByTransactionId(transactionId);

            //退款成功
            recharge.setRefundStatus(1);
            //修改剩余余额
            recharge.setRemainingAmount(new BigDecimal(0));
            refundOrder.setStatus("SUCCESS");
            //退款金额
            refundOrder.setPayerRefund(new BigDecimal(refundAmount));
            refundOrder.setRefund(new BigDecimal(refundAmount));
            refundOrderService.updateById(refundOrder);
            rechargeService.updateById(recharge);
            //退款成功 生成退款记录
            BalanceChange balanceChange = new BalanceChange();
            //用户id
            balanceChange.setMemberId(recharge.getMemberId());
            //类型 收入
            balanceChange.setType(1);
            //备注
            balanceChange.setRemarks("余额退款");
            //金额
            balanceChange.setAmount(recharge.getRefundAmount());
            //变动之前
            balanceChange.setBalanceBefore(new BigDecimal(0));
            //变动之后
            balanceChange.setBalanceAfter(new BigDecimal(0));
            //场景 退款成功 7
            balanceChange.setScene(7);
            //渠道
            balanceChange.setChannel(recharge.getChannel());
            balanceChangeService.add(balanceChange);

            //发送订阅消息
            //sendSubscriptionMessage( recharge);
        } catch (Exception e) {
            log.error("汇付退款回调报错，参数:" + data);
            log.error("汇付退款回调报错，报错信息:" + e);
        }

        return "RECV_ORD_ID_" + reqSeqId;
    }

    /**
     * 汇付申请退款
     *
     * @return
     */
    @Override
    public ResponseResult refunds() {


        //查询支付渠道是3,4的退款订单 sql if判断一下如果是3 就用in (3,4)

        List<Recharge> rechargeList = rechargeService.selectByRemainingAmountByPaymentChannel(3);
        if (rechargeList.size() == 0) {
            return new ResponseResult(200, true);
        }

        RefundOrder refundOrder = new RefundOrder();
        for (Recharge recharge : rechargeList) {

            //如果退款金额是0  不需要管
            if (recharge.getRemainingAmount().compareTo(new BigDecimal(0)) == 0) {
                recharge.setRefundStatus(1);
                rechargeService.updateById(recharge);
                //交易确认退款接口
                confirm(recharge);
                continue;
            }
            String replaceUUID = UUID.randomUUID().toString().replace("-", "");
            //支付宝支付订单号
            refundOrder.setTransactionId(recharge.getThirdOrderNumber());
            //商户退款单号
            refundOrder.setOutRefundNo(replaceUUID);
            //电站id
            refundOrder.setStationId(recharge.getStationId());
            refundOrderService.add(refundOrder);
            //如果是  汇付退款
            //汇付退款逻辑方法
            weiLaiElectricWeChatRefund(recharge, replaceUUID, refundOrder);
            //交易确认退款接口
            confirm(recharge);
        }
        return new ResponseResult(200, false);
    }


    /**
     * 汇付退款逻辑
     *
     * @param recharge
     * @param replaceUUID
     * @param refundOrder
     */
    private void weiLaiElectricWeChatRefund(Recharge recharge, String replaceUUID, RefundOrder refundOrder) {


        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Map map = new HashMap();
        map.put("req_date", sdf.format(new Date()));
        //我们自己生成的 退款订单号
        map.put("req_seq_id", replaceUUID);
        //汇付ID
        map.put("huifu_id", recharge.getMchId());

        //退款金额
        map.put("ord_amt", String.valueOf(recharge.getRemainingAmount().setScale(2, RoundingMode.HALF_UP)));
        //原交易请求日期  支付时间
        map.put("org_req_date", sdf.format(recharge.getPaymentTime()));
        //微信支付单号
        map.put("org_party_order_id", recharge.getPartyOrderId());

        map.put("notify_url", refundsNotify);
        String jsonString = JSON.toJSONString(JSONObject.parseObject(JSONUtil.toJsonStr(map), TreeMap.class));
        //获取sign
        String sign = HuiFuVerificationSignatures.sign(jsonString, HuiFuConstants.RSA_PRIVATE_KEY);
        CommonParameters commonParameters = new CommonParameters<>();
        commonParameters.setSign(sign);
        commonParameters.setData(map);
        commonParameters.setSys_id(HuiFuConstants.SYS_ID);
        commonParameters.setProduct_id(HuiFuConstants.PRODUCT_ID);
        String returnResultsString = HttpClientUtil.doPostJson("https://api.huifu.com/v2/trade/payment/scanpay/refund", JSONUtil.toJsonStr(commonParameters));
        JSONObject jsonObject = JSON.parseObject(returnResultsString);

        //验签
        String data = jsonObject.get("data").toString();

        JSONObject dataObj = JSON.parseObject(data);
        log.info("汇付退款回调参数:" + dataObj);
        List<String> respCodeList = new ArrayList<>();
        respCodeList.add("00000100");
        respCodeList.add("00000000");
        if (!respCodeList.contains(dataObj.get("resp_code").toString())) {
            log.error("汇付退款失败了:" + dataObj);
            //退款失败
            recharge.setRefundStatus(3);
            rechargeService.updateById(recharge);
            refundOrder.setStatus("失败");
            String reasonFailureReason = "退款失败了";
            if (jsonObject.get("resp_desc") != null) {
                reasonFailureReason = (String) jsonObject.get("bank_message");
            }
            refundOrder.setReasonFailureReason((reasonFailureReason));
            refundOrderService.updateById(refundOrder);
            //退款失败了发送邮件

            //发送邮件
            String to = "709286540@qq.com";
            String title = "汇付退款失败";
            String content = "充值订单号:" + recharge.getThirdOrderNumber();
            emailUtil.sendMessage(to, title, content);

            return;
        }
        //退款成功 修改状态为 退款中  有回调
        //退款中
        recharge.setRefundStatus(2);
        recharge.setRefundAmount(recharge.getRemainingAmount().add(recharge.getRefundAmount()));
        rechargeService.updateById(recharge);

    }


    /**
     * 交易确认退款接口
     *
     * @param recharge
     */
    private void confirm(Recharge recharge) {
        //如果分账金额是0  直接返回
        if (recharge.getLedgerAmount().compareTo(new BigDecimal(0)) == 0) {
            recharge.setLedgerStatus(1);
            recharge.setLedgerTime(new Date());
            rechargeService.updateById(recharge);
            return;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Map map = new HashMap();

        String replaceUUID = UUID.randomUUID().toString().replace("-", "");
        map.put("req_date", sdf.format(new Date()));
        map.put("req_seq_id", replaceUUID);
        map.put("huifu_id", recharge.getMchId());
        map.put("org_req_date", sdf.format(recharge.getPaymentTime()));
        map.put("org_req_seq_id", recharge.getRechargeOrderNo());

        String jsonString = JSON.toJSONString(JSONObject.parseObject(JSONUtil.toJsonStr(map), TreeMap.class));
        //获取sign
        String sign = HuiFuVerificationSignatures.sign(jsonString, HuiFuConstants.RSA_PRIVATE_KEY);
        CommonParameters commonParameters = new CommonParameters<>();
        commonParameters.setSign(sign);
        commonParameters.setData(map);
        commonParameters.setSys_id(HuiFuConstants.SYS_ID);
        commonParameters.setProduct_id(HuiFuConstants.PRODUCT_ID);
        String returnResultsString = HttpClientUtil.doPostJson("https://api.huifu.com/v2/trade/payment/delaytrans/confirm", JSONUtil.toJsonStr(commonParameters));
        JSONObject jsonObject = JSON.parseObject(returnResultsString);
        //验签
        String data = jsonObject.get("data").toString();

        JSONObject dataObj = JSON.parseObject(data);
        log.info("汇付交易确认返回参数:" + dataObj);

        List<String> respCodeList = new ArrayList<>();
        respCodeList.add("00000000");
        if (!respCodeList.contains(dataObj.get("resp_code").toString())) {
            log.error("汇付交易确认失败" + recharge.getPartyOrderId());
            //交易确认失败  充值订单分账状态修改为失败
            recharge.setLedgerStatus(3);
        } else {
            //默认分账成功
            recharge.setLedgerStatus(1);
            recharge.setLedgerTime(new Date());
        }
        rechargeService.updateById(recharge);
    }


}
